package org.jeecg.modules.utils;


import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.util.Arrays;

public class MD5Utils {
	private static final String ALGORITH_NAME = "md5";
	private static final int HASH_ITERATIONS = 2;

    //解密
	public static String encrypt(String password) {
		return new SimpleHash(ALGORITH_NAME, password, ByteSource.Util.bytes(password), HASH_ITERATIONS).toHex();
	}

	/**
	 * 加密文件 byte[] 转为 32为 加密字符
	 * @param str
	 * @return 异或加密字符串
	 */
	public static String bytesToMd5String(byte[] str) {
		try {
			// 生成一个MD5加密计算摘要
			MessageDigest md = MessageDigest.getInstance("MD5");
			// 计算md5函数
			md.update(str);
			// digest()最后确定返回md5 hash值，返回值为8为字符串。因为md5 hash值是16位的hex值，实际上就是8位的字符
			// BigInteger函数则将8位的字符串转换成16位hex值，用字符串来表示；得到字符串形式的hash值
			String md5=new BigInteger(1, md.digest()).toString(16);
			//BigInteger会把0省略掉，需补全至32位
			//异或加密
			return stringToXor(fillMD5(md5));
		} catch (Exception e) {
			throw new RuntimeException("MD5加密错误:"+e.getMessage(),e);
		}
	}
	/**
	 * 加密文件 byte[] 转为 32为 加密字符
	 * @param md5
	 * @return string 异或加秘 字符串
	 */
	private static String stringToXor(String md5) {
		byte[] md5ValueHex = hex2Bytes(md5);
		for(int i = 0; i < 16; i++){
			int n = md5ValueHex[i] ^ 0x7F;
			md5ValueHex[i] = (byte)n;
		}
		return bytes2HexString(md5ValueHex);
	}
	/**
	 * 加密文件 byte[] 转为 32为 加密字符
	 * @param str
	 * @return 异或加密字符串
	 */
	public static String bytesToMd5PileString(byte[] str) {
		try {
			// 生成一个MD5加密计算摘要
			MessageDigest md = MessageDigest.getInstance("MD5");
			// 计算md5函数
			md.update(str);
			// digest()最后确定返回md5 hash值，返回值为8为字符串。因为md5 hash值是16位的hex值，实际上就是8位的字符
			// BigInteger函数则将8位的字符串转换成16位hex值，用字符串来表示；得到字符串形式的hash值
			String md5=new BigInteger(1, md.digest()).toString(16);
			//BigInteger会把0省略掉，需补全至32位
			//异或加密
			return stringToXor3E(fillMD5(md5));
		} catch (Exception e) {
			throw new RuntimeException("MD5加密错误:"+e.getMessage(),e);
		}
	}
	/**
	 * 加密文件 byte[] 转为 32为 加密字符
	 * @param md5
	 * @return string 异或加秘 字符串
	 */
	private static String stringToXor3E(String md5) {
		byte[] md5ValueHex = hex2Bytes(md5);
		for(int i = 0; i < 16; i++){
			int n = md5ValueHex[i] ^ 0x3E;
			md5ValueHex[i] = (byte)n;
		}
		return bytes2HexString(md5ValueHex);
	}
	/**
	 * 十六进制转为byte数组
	 *
	 * @param hex 十六进制字符串
	 * @return byte数组
	 */
	public static byte[] hex2Bytes(String hex) {
		if (hex.length() < 1) {
			return null;
		} else {
			byte[] result = new byte[hex.length() / 2];
			int j = 0;
			for (int i = 0; i < hex.length(); i += 2) {
				result[j++] = (byte) Integer.parseInt(hex.substring(i, i + 2), 16);
			}
			return result;
		}
	}

	/**
	 * 十六进制byte数组转为十六进制字符串
	 *
	 * @param bytes 十六进制byte数组
	 * @return 十六进制字符串
	 */
	public static String bytes2HexString(byte[] bytes) {
		StringBuffer sb = new StringBuffer(bytes.length);
		String sTmp;

		for (int i = 0; i < bytes.length; i++) {
			sTmp = Integer.toHexString(0xFF & bytes[i]);
			if (sTmp.length() < 2) {
				sb.append(0);
			}
			sb.append(sTmp.toUpperCase());
		}

		return sb.toString();
	}

	/**
	 * 	需补全至32位
	 */
	private static String fillMD5(String md5){
		//如果不够32位则回调自身补零，最后返回32位长度的签名
		return md5.length()==32?md5:fillMD5("0"+md5);
	}
}
